package com.atguigu.gmall.index.service;

import com.atguigu.core.bean.Resp;
import com.atguigu.gmall.index.annotation.GmallCache;
import com.atguigu.gmall.index.feign.GmallPmsClient;
import com.atguigu.gmall.pms.entity.CategoryEntity;
import com.atguigu.gmall.pms.vo.CategoryVO;
import org.apache.commons.lang.StringUtils;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class IndexService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private final static String KEY_PROFIX = "index:cates:";

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private GmallPmsClient gmallPmsClient;

    public List<CategoryEntity> queryLvllCategories() {
        Resp<List<CategoryEntity>> listResp = gmallPmsClient.queryCategoriesByPidOrLevel(1, null);
        return listResp.getData();
    }

    @GmallCache(prefix = "index:cates:",timeout = 7200,random = 100)
    public List<CategoryVO> querySubCategories(Long pid) {
        // 1 .判断缓存有没有
//        String cateJson = this.redisTemplate.opsForValue().get(KEY_PROFIX + pid);
        // 2. 有就直接返回
//        if (!StringUtils.isEmpty(cateJson)) {
//            return JSON.parseArray(cateJson, CategoryVO.class);
//        }

//        RLock lock = this.redissonClient.getLock("lock" + pid);
//        lock.lock();

        // 1 .判断缓存有没有
//        String cateJson2 = this.redisTemplate.opsForValue().get(KEY_PROFIX + pid);
        // 2. 有就直接返回
//        if (!StringUtils.isEmpty(cateJson2)) {
//            lock.unlock();
//            return JSON.parseArray(cateJson2, CategoryVO.class);
//        }

        //查询数据库
        Resp<List<CategoryVO>> listResp = gmallPmsClient.querySubCategories(pid);
        List<CategoryVO> categoryVOS = listResp.getData();
        //3.查询完成后放入缓存
//        this.redisTemplate.opsForValue().set(KEY_PROFIX + pid, JSON.toJSONString(categoryVOS), 7 + new Random().nextInt(5), TimeUnit.DAYS);

//        lock.unlock();

        return listResp.getData();
    }

    /*
     *   锁
     * 1.互斥性
     * 2.获取锁并设置过期时间防止死锁 ,要具备原子性 释放锁也要具备原子性
     * 3.解铃还需系铃人
     */
    public void testLock() {
        RLock lock = this.redissonClient.getLock("lock");
        lock.lock();

        String numString = this.redisTemplate.opsForValue().get("num");
        if (StringUtils.isEmpty(numString)) {
            return;
        }
        int num = Integer.parseInt(numString);
        this.redisTemplate.opsForValue().set("num", String.valueOf(++num));
        lock.unlock();
    }

    public String testRead() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
        rwLock.readLock().lock(101, TimeUnit.SECONDS);
        String s = this.redisTemplate.opsForValue().get("test");
        rwLock.readLock().unlock();
        return s;
    }

    public String testWrite() {
        RReadWriteLock rwLock = this.redissonClient.getReadWriteLock("rwLock");
        rwLock.writeLock().lock(101, TimeUnit.SECONDS);
        this.redisTemplate.opsForValue().set("test", UUID.randomUUID().toString());
        return "写入数据";
    }

    public String testLatch() throws InterruptedException {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.trySetCount(5);
        latch.await();
        return "主业务开始执行.....";
    }

    public String testCountdown() {
        RCountDownLatch latch = this.redissonClient.getCountDownLatch("latch");
        latch.countDown();
        return "分支业务开始执行......";
    }
}
